package com.dmall.client.controller;

import com.dmall.client.pojo.User;
import com.dmall.client.proxy.UserServiceProxy;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@RequestMapping("/user/client")
@Slf4j
// 为整个类设置默认属性，设置默认的降级方法
@DefaultProperties(defaultFallback = "getFallback")
public class UserController {

    /**
     * 使用ribbon配置负载均衡的方式：
     * 首先要引入ribbon的依赖：
     *      <dependency>
     *          <groupId>org.springframework.cloud</groupId>
     *          <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
     *      </dependency>
     * 第一种方式：
     *      注入RibbonLoadBalancerClient，在调用服务的时候使用RibbonLoadBalancerClient#choose方法传入服务ID，调用服务
     *      choose方法只会返回一个服务的实例，拿到服务实例后就可以得到服务的host和port，然后就可以通过RestTemplate进行调用
     * 第二种方式：
     *      在配置RestTemplate的地方使用@LoadBalanced注解标注一下
     *      然后在调用服务的时候，我们将url的host和port改为服务的id进行调用
     *      这种方式的负载均衡的实现是有一个负载均衡的拦截器（LoadBalancerInterceptor）去实现的
     *      LoadBalancerInterceptor拦截器底层也是使用RibbonLoadBalancerClient去实现负载均衡的
     *      默认也是使用轮询的方式
     *      要想该默认的负载均衡方式，需要在服务消费者的application.yml中配置
     *          user-service: #服务id
     *              ribbon:
     *                  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
     *      需要注意：是在服务消费者的配置文件中配置
     */

    /*@GetMapping("{id}")
    public User get(@PathVariable("id") Integer id) {
        List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
        ServiceInstance instance = instances.get(0);
        String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/user/" + id;
        User user = restTemplate.getForObject(url, User.class);
        return user;
    }*/

    // 第一种方式：
    /*@GetMapping("{id}")
    public User get(@PathVariable("id") Integer id) {
        // bibbon默认的负载均衡策略是：轮询
        ServiceInstance instance = balancerClient.choose("user-service");
        String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/user/" + id;
        User user = restTemplate.getForObject(url, User.class);
        return user;
    }*/

    // 第二种方式：
    /*@GetMapping("/{id}")
    public User get(@PathVariable("id") Integer id) {
        String url = "http://user-service/user/" + id;
        User user = restTemplate.getForObject(url, User.class);
        return user;
    }*/

    @GetMapping("/{id}")
    // 可以通过@HystrixCommand注解设置服务降级或服务熔断的一些属性，属性的名称参考HystrixCommandProperties类
    //@HystrixCommand(commandProperties = @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2500"))
    // 这种方式是局部配置，当然也可以全局配置，可以在application.yml中进行如下配置：
    /**
     * hystrix:
     *   command:
     *     default:
     *       execution:
     *         isolation:
     *           thread:
     *             timeoutInMilliseconds: 2500
     */
    /*@HystrixCommand(commandProperties = {
            // 触发熔断的最小请求次数，默认20
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            // 休眠时长，默认是5000毫秒
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
            // 触发熔断的失败请求最小占比，默认50%
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
    })*/
    public User get(@PathVariable("id") Integer id) {
        /*if (id % 2 == 0) {
            throw new RuntimeException("");
        }
        String url = "http://user-service/user/" + id;
        String user = restTemplate.getForObject(url, String.class);
        return user;*/
        return userServiceProxy.get(id);
    }

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private UserServiceProxy userServiceProxy;

    /*@Autowired
    private RibbonLoadBalancerClient balancerClient;*/

    public String getFallback() {
        // log.error("根据用户ID查询用户失败，id={}", id);
        return "对不起，服务器太繁忙了";
    }
}
